<?php
/**
 * Created by PhpStorm.
 * User: admin
 * Date: 2019/11/4
 * Time: 13:37
 */

namespace app\adminapiv3\service;


use app\common\service\HostRule;
use app\common\service\ServerDownloadLog;
use app\common\netfilter\Rule;

class ServerDownload extends Base
{
    public $moduleFilePath = array(
        //3=>hostkey下载 4=>linux安装包下载 5=>windows安装包下载 6=>linux更新包 7windows更新包,8网络日志数据包
        3 => 'static/host/hostkey.key',
        4 => 'static/InstallPackage/linux/Install.sh',
        5 => 'static/InstallPackage/windows/windows.exe',
    );
    /**
     * @name 列表
     * @param int $module
     * @param int $limit
     * @return array
     * @author wx
     * @date 2019/11/4 13:53
     */
    function list($module = 1, $limit = 10)
    {
        $server = new \app\common\service\ServerDownload();
        $list = $server->list($module, $limit);

        foreach($list['data'] as $k => $v){
            $v['ctime'] = date('Y-m-d H:i:s', $v['ctime']);
            $list['data'][$k] = $v;
        }

        return $list;
    }

    function del($module = 1, $id)
    {
        //1. 删除文件
        $this->delFile($module, $id);

        //2. 删除数据
        $server = new \app\common\service\ServerDownload();
        $server->del($module, $id);

        return true;
    }

    /**
     * @name 删除文件
     * @param $module 1=>Netfilter日志 2=>规则 3=>hostkey下载 4=>linux安装包下载 5=>windows安装包下载 6=>linux更新包 7windows更新包
     * @param $id
     * @return bool
     * @author wx
     * @date 2019/11/4 14:02
     */
    function delFile($module, $id)
    {
        $canModule = array(1, 2);
        if (!in_array($module, $canModule)) {
            $this->setError($this->CODE_FAIL, '此模块文件不允许删除');
            return false;
        }

        $server = new \app\common\service\ServerDownload();

        $info = $server->findData(['module' => $module, 'id' => $id]);
        if (!$info) {
            $this->setError($this->CODE_FAIL, '未找到该数据');
            return false;
        }

        //删除文件
        if (file_exists($info['path'])) {
            unlink($info['path']);
        }

        return true;
    }

    /**
     * @name 下载
     * @param int $module
     * @param int $id
     * @return array|bool|null|\PDOStatement|string|\think\Model
     * @author wx
     * @date 2019/12/27 10:10
     */
    function download($module = 1, $id = 0)
    {
        //1. 判断当前模块
        $canModule = array(1, 2);//日志文件
        if (in_array($module, $canModule)) {
            //查询当前文件状态
            $server = new \app\common\service\ServerDownload();
            $condition['id'] = $id;
            $condition['module'] = $module;
            $condition['status'] = 2;//已完成
            $info = $server->findData($condition,'path');
        }else{

            if($module == 3){//hostkey下载
                $authServer = new ServerAuth();
                $authServer->createHostFile();
            }

            if (array_key_exists($module, $this->moduleFilePath)) {
                $info['path'] = $this->moduleFilePath[$module];
            }
        }

        if(!isset($info['path']) || !file_exists($info['path'])){
            $this->setError($this->CODE_FAIL, '未查询到数据');
            return false;
        }


        $userInfo = $this->getUserInfo();
        //2. 加入下载记录
        $addData = array(
            'download_id' => $id,
            'user_id' => $userInfo['id'],
            'module' => $module,
            'path' => $info['path'],
            'ip' => $_SERVER['REMOTE_ADDR'],
            'ctime' => time()
        );

        $serverDownloadLog = new ServerDownloadLog();
        $serverDownloadLog->add($addData);

        //返回服务端ip和端口号
        $info['ip'] = $_SERVER['SERVER_ADDR'];
        $info['port'] = $_SERVER['SERVER_PORT'];

        //3. 返回
        return $info;
    }


    /**
     * @name 根据模块返回参数
     * @param $module
     * @return array
     * @author wx
     * @date 2019/11/5 10:44
     */
    function createModule($module)
    {
        //1. 检查模块
        $canModule = array(1, 2);
        if (!in_array($module, $canModule)) {
            $this->setError($this->CODE_FAIL, '此模块不允许创建下载任务');
            return false;
        }

        if($module == 1){
            //netfileter日志
            $params = array(
                'host_id',
                'start_time',
                'end_time'
            );
        }else{
            //规则
            $params = array(
                'host_id'
            );
        }

        return $params;
    }


    function create($module, $request)
    {

        //2. 添加下载数据
        $addData['host_id'] = $request['host_id'];
        $addData['module'] = $module;
        $addData['ratio'] = 0;
        $addData['path'] = '';
        $addData['ctime'] = time();
        $addData['status'] = 0;
        $addData['start_time'] = isset($request['start_time']) ? strtotime($request['start_time']) : 0;
        $addData['end_time'] = isset($request['end_time']) ? strtotime($request['end_time']) : 0;

        $server = new \app\common\service\ServerDownload();
        $downloadId = $server->add($addData);

        $addData['id'] = $downloadId;

        if($module == 1){//netfilter日志
            $this->netfilterLog($addData);
        }else{//rule
            $this->rule($addData);
        }

        //3. 执行创建下载操作
        //$this->sendUrl($downloadId ,$module);

        return true;
    }

    /**
     * @name 导出规则
     * @param $info
     * @author wx
     * @date 2019/11/5 17:02
     */
    function rule ($info)
    {
        //1. 修改任务状态
        db('server_download')->where(['id' => $info['id']])->update(['status' => 1]);
        //2. 查询规则

        //3. 处理规则
        //4. 写入文件
        //5. 修改任务状态
        //6. 返回
        $hostId_s = $info['host_id'];
        $hostId_a = explode(',', $hostId_s);
        $allCount = count($hostId_a);

        //创建目录
        $path =  '../runtime/Download/iptableList/';
        file_exists($path) ? : mkdir($path,0777, true);

        $netfilterServer = new Netfilter();
        $index = 1;
        foreach ($hostId_a as $k => $hostId) {//循环写入文件
            $ip = db('host_contact')->where('host_id',$hostId)->value('ip');

            $ipArr[] = $ip;

            $file_name = $path.$ip.'.txt';

            $fp = fopen($file_name,'w');

            $page = 0;//当前页数
            do{
                $offset = $page * 300;
                $list = db('HostRule')->where('host_id', $hostId)
                    ->order('id desc')
                    ->limit($offset, 300)->select();
                $fid_a = array_column($list, 'fid');
                $hostRuleServer = new HostRule();

                $childData = $hostRuleServer->childList($hostId, $fid_a);
                $data = $netfilterServer->processOut($childData);

                $ruleServer = new Rule($hostId);
                $logData = $ruleServer->firewallRule($data);//具体日志规则


                if($logData){
                    foreach ($logData as $v) {
                        fwrite($fp, $v.PHP_EOL);
                    }
                    // 写入并关闭资源
                    $page++;
                }
            }while($list);

            fclose($fp);


            $index++;
        }


        //下载路径
        $downloadPath = 'download/iptablesRule/'.date('Y-m-d').'/';
        $this->createZip($ipArr, $info,$downloadPath, $path,'.txt');


    }

    function netfilterLog($info)
    {
        //创建目录--标题处理
        $path = '../runtime/Download/netfilterLog/';//生成日志文件
        file_exists($path)? :mkdir($path,0777,true);
        $csv_header = array(
            '序号',
            '主机id',
            '来源ip',
            '目标ip',
            '方向',
            '目标端口',
            '端口类型',
            '是否授权访问',
            '首次访问时间',
            '最后访问时间',
            '是否忽略',
            '是否伪装端口',
            '访问总数',
        );
        $header = implode(',', $csv_header) . PHP_EOL;
        $header = iconv('UTF-8','GBK',$header);
        $host_arr = explode(',', $info['host_id']);
        $host_count = count($host_arr);

        //修改状态
        db('server_download')->where(['id' => $info['id']])->update(['status' => 1]);


        $index = 1;
        //查询数据 --循环主机
        foreach ($host_arr as $value){
            $ip = db('host_contact')->where('host_id',$value)->value('ip');
            $ipArr[] = $ip;

            $db = db('host_access_log');//数据库连接

            //时间筛选
            if($info['end_time'] != 0){
                $db->where('last_time','between', [$info['start_time'], $info['end_time']]);
            }elseif($info['start_time'] != 0 && $info['end_time'] == 0){
                $db->where('last_time','>=', $info['start_time']);
            }

            //寻找数据
            // 打开文件资源，不存在则创建
            $file_name = $path.$ip.'.csv';
            $fp = fopen($file_name,'w');
            fwrite($fp, $header);//写入标题
            $page = 0;//当前页数
            $num = 1;//序号
            do{
                $offset = $page * 300;
                $list = $db->where('host_id',$value)
                    ->field('syslog, elk', true)
                    ->order('id desc')
                    ->limit($offset, 300)
                    ->select();

                if($list){
                    // 处理内容
                    $content = '';
                    foreach ($list as $v) {
                        array_unshift($v, $num);
                        unset($v['id']);
                        if($v['direction'] == 1){
                            $v['direction'] = '出站';
                        }else{
                            $v['direction'] = '入站';
                        }
                        if($v['protocols'] == 1){
                            $v['protocols'] = 'tcp';
                        }else{
                            $v['protocols'] = 'udp';
                        }
                        if($v['permission'] == 0){
                            $v['permission'] = '未授权';
                        }else{
                            $v['permission'] = '授权';
                        }
                        if($v['ignore'] == 0){
                            $v['ignore'] = '不忽略';
                        }else{
                            $v['ignore'] = '忽略';
                        }
                        if($v['guise'] == 0){
                            $v['guise'] = '不是';
                        }else{
                            $v['guise'] = '是';
                        }
                        $v['first_time'] = date('Y年m月d日 H:i:s', $v['first_time']);
                        $v['last_time'] = date('Y年m月d日 H:i:s', $v['last_time']);
                        $content .= implode(',', $v) . PHP_EOL;
                        $num++;
                    }
                    $content = iconv('UTF-8','GBK',$content);//改变编码
                    // 写入并关闭资源
                    fwrite($fp, $content);
                    $page++;
                }
            }while($list);

            fclose($fp);

            //更新进度状态

            $index++;
        }

        //生成压缩包
        $downloadPath = 'download/netfilterLog/'.date('Y-m-d').'/';
        $this->createZip($ipArr, $info, $downloadPath, $path,'.csv');
    }

    function createZip($ipArr, $info, $downloadPath, $runtimePath, $suffix)
    {
        file_exists($downloadPath)? : mkdir($downloadPath,0777,true);
        $zipName = $downloadPath.$info['id'].'_'.time().'.zip';//zip文件名
        $zip = new \ZipArchive;

        if ($zip->open($zipName, \ZIPARCHIVE::OVERWRITE | \ZIPARCHIVE::CREATE)!==TRUE) {
            return 0;
        }

        //------生成压缩包----
        $files = scandir($runtimePath);
        foreach ($files as $file){
            if($file == '.' || $file == '..'){
                continue;
            }
            $fileName = basename($file, $suffix);
            if (in_array($fileName, $ipArr)) {
                $nowFile = $runtimePath.$fileName.$suffix;//文件位置
                //添加到zip中
                if(file_exists($nowFile)){
                    //将文件添加到zip压缩包中
                    $zip->addFile($nowFile, basename($nowFile));
                }
            }
        }
        $zip->close();//关闭

        $server = new \app\common\service\ServerDownload();
        //2成功
        return $server->modify(['id' => $info['id']], ['path' => $zipName, 'ratio' => 100, 'status' => 2]);
    }

    /**
     * @name: 发送任务请求
     * @Param:
     * @Description:
     * @Author: foo
     * @Date: 2019-05-05 14:07:42
     */
    function sendUrl ($downloadId, $module)
    {
        $downloadAction = [
            1 => 'api/v3/export/netfilter',//导出防火墙日志
            2 => 'api/v3/export/rule',//导出主机规则
        ];

        $action = isset($downloadAction[$module]) ? $downloadAction[$module] : 'login';

        $url = 'http://' . $_SERVER['HTTP_HOST']. '/'.$action;

        $postData = [
            'id' => $downloadId,
            'module' => $module,
        ];

        curlPost($url, $postData);
    }



}